# coding:utf-8
from sqlalchemy import or_

from . import api
from ihome.utils.commons import login_required
from flask import g, current_app, jsonify, request, session
from ihome.utils.response_code import RET
from ihome.models import Province, City, Area, User, Order, House, Facility, HouseImage, HouseCollection
from ihome import db, constants, redis_store
import json


#  获取省市区的数据需要保存到数据库中
# 默认为get方式
@api.route("/province")
def get_province_info():
    """获取当前的省份信息"""
    # 从redis中获取数据
    try:
        resp_json = redis_store.get("province_info")
    except Exception as e:
        current_app.logger.error(e)
    else:
        if resp_json is not None:
            current_app.logger.info("redis province_info")
            return resp_json, 200, {"Content-Type": "application/json"}
    try:
        province_ls = Province.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    province_dict_ls = []
    # 将对象转化为字典
    for province in province_ls:
        province_dict_ls.append(province.to_dict())

    # 将数据转化为json字符串为了保存到redis中
    resp_dict = dict(errno=RET.OK, errmsg="OK", data=province_dict_ls)
    resp_json = json.dumps(resp_dict)

    # 将数据保存到redis中
    try:
        redis_store.setex("province_info", constants.PROVINCE_CITY_AREA_INFO_REDIS_CACHE_EXPIRES, resp_json)
    except Exception as e:
        current_app.logger.error(e)
    # 使用字典的方式返回响应信息
    #       响应体    状态码       响应头
    return resp_json, 200, {"Content-Type": "application/json"}


# 根据查询的省份id 查询对应的城市

@api.route("/city")
def get_city_info():
    """获取当前的省份的城市"""
    # 从redis中获取数据
    #
    # image_code_id = request.args.get("image_code_id")
    # 需要前端传回获取到的省份id 使用get数据传递
    province_id = request.args.get("pid")
    if province_id is None:
        return jsonify(errno=RET.REQERR, errmsg="参数不完整")

    try:
        resp_json = redis_store.get("city_info_%s" % province_id)
    except Exception as e:
        current_app.logger.error(e)
    else:
        if resp_json is not None:
            current_app.logger.info("redis city_info_%s" % province_id)
            return resp_json, 200, {"Content-Type": "application/json"}
    try:
        city_ls = City.query.filter_by(p_id=province_id).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    city_dict_ls = []
    # 将对象转化为字典
    for city in city_ls:
        city_dict_ls.append(city.to_dict())

    # 将数据转化为json字符串为了保存到redis中
    resp_dict = dict(errno=RET.OK, errmsg="OK", data=city_dict_ls)
    resp_json = json.dumps(resp_dict)

    # 将数据保存到redis中
    try:
        redis_store.setex("city_info_%s" % province_id, constants.PROVINCE_CITY_AREA_INFO_REDIS_CACHE_EXPIRES,
                          resp_json)
    except Exception as e:
        current_app.logger.error(e)
    # 使用字典的方式返回响应信息
    #       响应体    状态码       响应头
    return resp_json, 200, {"Content-Type": "application/json"}


@api.route("/area")
def get_area_info():
    """获取当前的省份的城市的区域"""
    # 从redis中获取数据
    # image_code_id = request.args.get("image_code_id")
    # 需要前端传回获取到的城市的id
    city_id = request.args.get("cid")
    if city_id is None:
        return jsonify(errno=RET.REQERR, errmsg="参数不完整")

    try:
        resp_json = redis_store.get("area_info_%s" % city_id)
    except Exception as e:
        current_app.logger.error(e)
    else:
        if resp_json is not None:
            current_app.logger.info("redis area_info_%s" % city_id)
            return resp_json, 200, {"Content-Type": "application/json"}
    try:
        area_ls = Area.query.filter_by(c_id=city_id).all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    area_dict_ls = []
    # 将对象转化为字典
    for area in area_ls:
        area_dict_ls.append(area.to_dict())

    # 将数据转化为json字符串为了保存到redis中
    resp_dict = dict(errno=RET.OK, errmsg="OK", data=area_dict_ls)
    resp_json = json.dumps(resp_dict)

    # 将数据保存到redis中
    try:
        redis_store.setex("area_info_%s" % city_id, constants.PROVINCE_CITY_AREA_INFO_REDIS_CACHE_EXPIRES, resp_json)
    except Exception as e:
        current_app.logger.error(e)
    # 使用字典的方式返回响应信息
    #       响应体    状态码       响应头
    return resp_json, 200, {"Content-Type": "application/json"}


@api.route("/house/get_facility")
def get_facility_info():
    """获取设备信息"""
    try:
        facility_info = Facility.query.all()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取设备信息")
    facility_list = []
    if facility_info:
        for facility in facility_info:
            facility_list.append(facility.to_dict())

    return jsonify(errno=RET.OK, errmsg="获取成功", data=facility_list)


@api.route("/house/info", methods=["POST"])
@login_required
def save_house_info():
    """
    保存房屋信息
    """
    # 获取数据
    user_id = g.user_id
    # 获取实名认证信息
    user_auth = User.query.filter_by(id=user_id).first()
    if user_auth.id_card is None:
        return jsonify(errno=RET.DATAERR, errmsg="未进行实名认证")

    house_data = request.get_json()
    title = house_data.get("title")  # 房屋名称标题
    area_id = house_data.get("area_id")  # 房屋所在地区 是一个数字
    month_price = house_data.get("house_rent")  # 月租
    address = house_data.get("address")  # 房屋地址
    acreage = house_data.get("acreage")  # 房屋面积
    house_type = house_data.get("house_type")  # 房屋户型
    lease_type = house_data.get("lease_type")  # 出租类型
    position = house_data.get("position")  # 方位朝向 可省略
    # floor = house_data.get('floor')  # 房屋楼层 前端暂未展示该字段 省略
    # unit = house_data.get("unit")  # 房屋单元 可省略
    renovation = house_data.get("house_renovation")  # 装修程度 可省略
    build_date = house_data.get("build_date")  # 建造时间 可省略
    see_house_date = house_data.get("see_house_date")  # 可看房时间 起租时间
    house_del = house_data.get("house_del")  # 房屋描述
    facility_ids = house_data.get("check_service")  # 房屋设备这里面是一个列表(数字集合)
    image_list = house_data.get("house_img_url")  # 房屋图片地址 这里面会是一个列表

    if not all([title, month_price, area_id, address, acreage, house_type, lease_type, see_house_date, house_del,
                renovation, facility_ids, image_list]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")

    # 判断城区id是否存在
    try:
        area = Area.query.get(area_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    if area is None:
        return jsonify(errno=RET.NODATA, errmsg="城区信息有误")

    for image in image_list:
        # 读取一个上传的第一张图片 当做房屋主页 读取一次就结束
        img_index = image["image_url"]
        break

    # 保存房屋信息
    house = House(
        user_id=user_id,
        title=title,
        area_id=area_id,
        month_price=month_price,
        address=address,
        acreage=acreage,
        house_type=house_type,
        lease_type=lease_type,
        build_date=build_date,
        see_house_date=see_house_date,
        house_del=house_del,
        position=position,
        renovation=renovation,
        index_image_url=img_index
    )

    # 如果用户勾选了设施信息，再保存数据库
    if facility_ids:
        # ["7","8"]
        try:
            # select  * from ih_facility_info where id in []
            # 查询勾选的数据是否来源于设备
            facilities = Facility.query.filter(Facility.id.in_(facility_ids)).all()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="数据库异常")

        if facilities:
            # 表示有合法的设施数据
            # 保存设施数据
            house.facilities = facilities

    try:
        db.session.add(house)
        db.session.flush()
        for image in image_list:
            # 保存图片信息到数据库中 image为字典类型
            house_image = HouseImage(house_id=house.id, url=image["image_url"])
            db.session.add(house_image)
        # house.id 可以直接获取到新建的house id 值
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存数据失败")

    # 保存数据成功
    return jsonify(errno=RET.OK, errmsg="发布成功", data={"house_id": house.id})


@api.route("/house/reserve_order", methods=["POST"])
@login_required
def save_order():
    """预约看房的订单"""
    user_id = g.user_id

    # 获取参数
    order_data = request.get_json()
    house_id = order_data.get("house_id")
    see_date = order_data.get("see_date")
    name = order_data.get("name")
    phone = order_data.get("phone")

    if not all([house_id, see_date, name, phone]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")

    # 查询房屋是否存在
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取房屋信息失败")
    if not house:
        return jsonify(errno=RET.NODATA, errmsg="房屋不存在")

    # 预订的房屋是否是房东自己的
    if user_id == house.user_id:
        return jsonify(errno=RET.ROLEERR, errmsg="不能预订自己的房屋")

    # 查询房屋是否已经出租
    if "空闲" != house.house_status:
        return jsonify(errno=RET.ROLEERR, errmsg="该房屋已经出租")

    # 防止重复预定房屋 取消了可以再次预约
    try:
        house = Order.query.filter(Order.house_id == house_id, Order.user_id == user_id,
                                   Order.status != "CANCELED",Order.status != "COMPLETE").first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取订单信息失败")
    if house:
        return jsonify(errno=RET.NODATA, errmsg="该用户已经预约")

    # 保存订单数据
    order = Order(
        house_id=house_id,
        user_id=user_id,
        see_date=see_date,
        name=name,
        phone=phone,
    )
    try:
        db.session.add(order)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="预约看房失败")
    return jsonify(errno=RET.OK, errmsg="预约看房成功", data={"order_id": order.id})


# 展示房屋信息 不需要登录
@api.route("/house/get_house_index", methods=["GET"])
def get_house_index():
    """"获取首页展示的房屋
    首先从redis中获取数据
    如果redis没有 则读取数据库中的记录并把记录存在redis中
    这边需要的操作是:
    1.要展示当前区域的房屋
    2.展示五条房屋基本信息
    3.测试开发阶段默认所选的地区为思明区
    """
    # 从缓存中尝试获取数据
    try:
        ret = redis_store.get("home_index_data")
    except Exception as e:
        current_app.logger.error(e)
        ret = None

    if ret:
        current_app.logger.info("hit house index info redis")
        # 因为redis中保存的是json字符串，所以直接进行返回
        return ret, 200, {"Content-Type": "application/json"}
    else:
        try:
            # 如果redis中没有数据 查询数据库，返回房屋订单数目最多的5条数据
            houses = House.query.order_by(House.order_count.desc()).limit(constants.HOME_INDEX_PAGE_MAX_HOUSES)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="查询数据失败")

        if not houses:
            return jsonify(errno=RET.NODATA, errmsg="查询无数据")

        houses_list = []
        for house in houses:
            houses_list.append(house.to_basic_dict())

        # 将数据转换为json，并保存到redis缓存
        houses_dict = dict(errno=RET.OK, errmsg="OK", data=houses_list)
        json_houses = json.dumps(houses_dict)  # "[{},{},{}]"
        try:
            redis_store.setex("home_index_data", constants.HOME_INDEX_DATA_REDIS_EXPIRES, json_houses)
        except Exception as e:
            current_app.logger.error(e)

        return json_houses, 200, {"Content-Type": "application/json"}


# 展示房屋详细信息 不需要登录
@api.route("/house/get_house_del", methods=["GET"])
def get_house_del():
    """获取房屋的详细信息"""

    user_id = session.get("user_id", "-1")

    house_id = request.args.get('house_id')

    # 校验参数
    if not house_id:
        return jsonify(errno=RET.PARAMERR, errmsg="参数缺失")

    # 先从redis缓存中获取信息
    # try:
    #     ret = redis_store.get("house_info_%s" % house_id)
    # except Exception as e:
    #     current_app.logger.error(e)
    #     ret = None
    # if ret:
    #     current_app.logger.info("hit house info redis")
    #     return ret, 200, {"Content-Type": "application/json"}

    # 查询数据库
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询数据失败")

    if not house:
        return jsonify(errno=RET.NODATA, errmsg="房屋不存在")

    # 将房屋对象数据转换为字典
    try:
        house_data = house.to_dict()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DATAERR, errmsg="数据出错")

    for item in house_data['collections']:
        if user_id == item:
            house_data['collections'] = 1
            break
    else:
        house_data['collections'] = 0

    # 存入到redis中
    # houses_dict_del = dict(errno=RET.OK, errmsg="OK", data=house_data, current_user=user_id)
    # json_house = json.dumps(houses_dict_del)
    # try:
    #     redis_store.setex("house_info_%s" % house_id, constants.HOUSE_DETAIL_REDIS_EXPIRE_SECOND, json_house)
    # except Exception as e:
    #     current_app.logger.error(e)
    #
    # return json_house, 200, {"Content-Type": "application/json"}

    return jsonify(errno=RET.OK, errmsg="OK", data=house_data, current_user=user_id)


@api.route("/houses/list")
def get_house_list():
    """获取房屋的列表信息（搜索页面）
        涉及到多条件的筛选 展示不适用 redis进行缓存 先进行mysql测试
    """
    area_id = request.args.get("aid")  # 区域编号
    sort_key = request.args.get("sort_key", "new")  # 排序关键字
    page = request.args.get("p")  # 页数
    vague = request.args.get("v")  # 模糊查询 房屋类型、装修类型、面积

    # 筛选条件
    # --价格区间
    price_high = request.args.get("price_high")  # 最高价格
    price_low = request.args.get("price_low")  # 最低价格
    house_type = eval(request.args.get("h_t_filter"))  # 房屋类型
    lease_type = eval(request.args.get("l_h_filter"))  # 出租类型
    check_service = eval(request.args.get("check_service"))  # 用户选择的设备
    # 判断区域id
    if area_id:
        try:
            area = Area.query.get(area_id)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.PARAMERR, errmsg="区域参数有误")
        if area is None:
            return jsonify(errno=RET.NODATA, errmsg="城区信息有误")

    # 处理页数
    try:
        page = int(page)
    except Exception as e:
        current_app.logger.error(e)
        page = 1

    # 获取缓存数据
    # redis_key = "house_%s" % area_id
    # try:
    #     resp_json = redis_store.hget(redis_key, page)
    # except Exception as e:
    #     current_app.logger.error(e)
    # else:
    #     if resp_json:
    #         return resp_json, 200, {"Content-Type": "application/json"}

    # 过滤条件的参数列表容器
    filter_params = []
    filter_params_two = []
    filter_params_three = []
    filter_params_four = []
    filter_params_five = []
    # 填充过滤参数
    # 时间条件
    # conflict_orders = None
    # 区域条件
    if area_id:
        filter_params.append(House.area_id == area_id)
    # 价格区间
    if price_high and price_low is not None:
        filter_params_two.append(House.month_price.between(price_low, price_high))
    # 房屋类型
    if house_type:
        filter_params_three.append(House.house_type.in_(house_type))
    # 出租类型
    if lease_type:
        print(type(lease_type))
        filter_params_four.append(House.lease_type.in_(lease_type))
    # 选择的设备
    if check_service:
        print(type(lease_type))
        # 把列表中所有的数字加上1
        check_service = [i + 1 for i in check_service]
        filter_params_five.append(House.facilities.any(Facility.id.in_(check_service)))

    house_query = House.query
    # 单关键字 多条件查询

    if vague:
        house_query = house_query.filter(
            or_(House.acreage.ilike("%" + vague + "%"), House.house_type.ilike("%" + vague + "%"),
                House.lease_type.ilike("%" + vague + "%")))

    # 查询数据库
    # 排序条件
    if sort_key == "2":
        house_query = house_query.filter(*filter_params).filter(*filter_params_two) \
            .filter(*filter_params_three).filter(*filter_params_four).filter(*filter_params_five) \
            .order_by(House.month_price.asc())
    elif sort_key == "3":
        house_query = house_query.filter(*filter_params).filter(*filter_params_two) \
            .filter(*filter_params_three).filter(*filter_params_four).filter(*filter_params_five) \
            .order_by(House.month_price.desc())
    else:  # 新旧
        house_query = house_query.filter(*filter_params).filter(*filter_params_two) \
            .filter(*filter_params_three).filter(*filter_params_four).filter(*filter_params_five) \
            .order_by(House.create_time.desc())

    # 处理分页paginate()函数为处理分页的函数
    try:
        #                               当前页数          每页数据量                              自动的错误输出
        page_obj = house_query.paginate(page=page, per_page=constants.HOUSE_LIST_PAGE_CAPACITY, error_out=False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="数据库异常")

    # 获取页面数据
    house_li = page_obj.items
    houses = []
    for house in house_li:
        houses.append(house.to_basic_dict())

    # 获取总页数
    total_page = page_obj.pages

    # resp_dict = dict(errno=RET.OK, errmsg="OK", data={"total_page": total_page, "houses": houses, "current_page": page})
    # resp_json = json.dumps(resp_dict)

    # if page <= total_page:
    #     # 设置缓存数据
    #     redis_key = "house_%s_%s" % (area_id, sort_key)
    #     # 哈希类型
    #     try:
    #         # redis_store.hset(redis_key, page, resp_json)
    #         # redis_store.expire(redis_key, constants.HOUES_LIST_PAGE_REDIS_CACHE_EXPIRES)
    #
    #         # 创建redis管道对象，可以一次执行多个语句
    #         pipeline = redis_store.pipeline()
    #
    #         # 开启多个语句的记录
    #         pipeline.multi()
    #
    #         pipeline.hset(redis_key, page, resp_json)
    #         pipeline.expire(redis_key, constants.HOUES_LIST_PAGE_REDIS_CACHE_EXPIRES)
    #
    #         # 执行语句
    #         pipeline.execute()
    #     except Exception as e:
    #         current_app.logger.error(e)

    return jsonify(errno=RET.OK, errmsg="OK", data={"total_page": total_page, "houses": houses, "current_page": page})


@api.route("/house/collection", methods=["POST"])
@login_required
def check_house_collection():
    """用户收藏或取消收藏中意的房源"""
    user_id = g.user_id
    # 获取参数
    house_data = request.get_json()
    house_id = house_data.get("house_id")
    is_collection = house_data.get("is_collection")

    if not house_data:
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")

    # 查询房屋是否存在
    try:
        house = House.query.get(house_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="获取房屋信息失败")
    if not house:
        return jsonify(errno=RET.NODATA, errmsg="房屋不存在")

    # 预订的房屋是否是房东自己的
    if user_id == house.user_id:
        return jsonify(errno=RET.ROLEERR, errmsg="不能收藏自己的房屋")

    # 判断用户是否已经收藏，如果已经收藏则返回
    if is_collection:
        del_collection = HouseCollection.query.filter_by(house_id=house_id, user_id=user_id).first()
        try:
            db.session.delete(del_collection)
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            db.session.rollback()
            return jsonify(errno=RET.DBERR, errmsg="取消收藏失败")
        return jsonify(errno=RET.OK, errmsg="取消收藏成功")
    else:
        collection = HouseCollection(
            house_id=house_data.get("house_id"),
            user_id=user_id
        )

        # try:
        #     # select  * from ih_facility_info where id in []
        #     # 查询要插入的用户id是否是该用户表里的用户
        #     collection_house = User.query.filter_by(id=user_id).all()
        # except Exception as e:
        #     current_app.logger.error(e)
        #     return jsonify(errno=RET.DBERR, errmsg="数据库异常")
        #
        # if collection_house:
        #     # 表示有合法的用户数据
        #     # 保存设施数据
        #     house.user_collections = collection_house

        # session.execute('insert into house_collection values(house_id:value,user_id:value_two)',
        #                 params={"value": user_id, "value_two": house_data.get("house_id")})

        try:
            db.session.add(collection)
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            db.session.rollback()
            return jsonify(errno=RET.DBERR, errmsg="收藏失败")
        return jsonify(errno=RET.OK, errmsg="收藏成功")
